﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JihankiLib
{
    /// <summary>
    /// 自販機インターフェイス
    /// </summary>
    public interface IJihanki : IObservable<JihankiMessage>
    {
        void Initialize(MoneyBoxMachine moneyBox, JihankiItemBoxMachine jihanItemBox);
        void Run();
    }

    /// <summary>
    /// 自販機
    /// </summary>
    public class Jihanki : IJihanki
    {
        protected List<IObserver<JihankiMessage>> observers = new List<IObserver<JihankiMessage>>();
        private MoneyBoxMachine mboxMachine = null;
        private JihankiItemBoxMachine itemBoxMachine = null;


        public Jihanki()
        {
        }

        public void Initialize(MoneyBoxMachine mboxMachine, JihankiItemBoxMachine itemBoxMachine)
        {
            this.mboxMachine = mboxMachine;
            this.itemBoxMachine = itemBoxMachine;
        }

        public void Run()
        {
            mboxMachine.Initialize(this);
            mboxMachine.AddedMoney += new EventHandler<AddedMoneyEventArgs>(mboxMachine_AddedMoney);
            mboxMachine.EmptyMoney += new EventHandler<MoneyStateChangedEventArgs>(mboxMachine_EmptyMoney);
            mboxMachine.LowerLimitOver += new EventHandler<MoneyStateChangedEventArgs>(mboxMachine_LowerLimitOver);
            mboxMachine.RejectedAllMoney += new EventHandler<RejectedAllMoneyEventArgs>(mboxMachine_RejectAllMoney);
            mboxMachine.UpperLimitOver += new EventHandler<MoneyStateChangedEventArgs>(mboxMachine_UpperLimitOver);
            itemBoxMachine.Initialize(this);
            itemBoxMachine.Empty += new EventHandler<JihanItemBoxNoticeEventArgs>(itemBoxMachine_Empty);
            itemBoxMachine.ItemPurchased += new EventHandler<JihanItemPurchasedEventArgs>(itemBoxMachine_ItemPurchased);
            itemBoxMachine.ItemReplenished += new EventHandler<JihanItemBoxNoticeEventArgs>(itemBoxMachine_ItemReplenished);

            observers.ForEach(ob => { ob.OnNext(new RunMessage()); });
        }

        void itemBoxMachine_ItemPurchased(object sender, JihanItemPurchasedEventArgs e)
        {
            observers.ForEach(ob => { ob.OnNext(new ItemPurchasedMessage() { Unit = e.Unit, Money = e.Value});});
        }

        void mboxMachine_UpperLimitOver(object sender, MoneyStateChangedEventArgs e)
        {
            observers.ForEach(ob => { ob.OnNext(new UpperLimitOverMessage() { MType = e.MoneyType }); });
        }

        void mboxMachine_RejectAllMoney(object sender, RejectedAllMoneyEventArgs e)
        {
            observers.ForEach(ob => { ob.OnNext(new RejectedAllMoneyMessage() { RejectedValue = e.RejectedValue}); });
        }

        void mboxMachine_LowerLimitOver(object sender, MoneyStateChangedEventArgs e)
        {
            observers.ForEach(ob => { ob.OnNext(new LowerLimitOverMessage() { MType = e.MoneyType }); });
        }

        void mboxMachine_EmptyMoney(object sender, MoneyStateChangedEventArgs e)
        {
            observers.ForEach(ob => { ob.OnNext(new EmptyMoneyMessage() { MType = e.MoneyType }); });
        }

        void mboxMachine_AddedMoney(object sender, AddedMoneyEventArgs e)
        {
            observers.ForEach(ob => { ob.OnNext(new AddedMoneyMessage() { Added = e.Added, Total = e.Total}); });
        }

        void itemBoxMachine_ItemReplenished(object sender, JihanItemBoxNoticeEventArgs e)
        {
            observers.ForEach(ob => { ob.OnNext(new ItemReplenishedMessage() { Unit = e.Unit}); });
        }

        void itemBoxMachine_ItemPurchased(object sender, JihanItemBoxNoticeEventArgs e)
        {
            observers.ForEach(ob => { ob.OnNext(new ItemPurchasedMessage() { Unit = e.Unit }); });
        }

        void itemBoxMachine_Empty(object sender, JihanItemBoxNoticeEventArgs e)
        {
            observers.ForEach(ob => { ob.OnNext(new JihanItemBoxEmptMessage() { Unit = e.Unit }); });
        }

        private class _Obsererver : IDisposable
        {
            private Jihanki parent;
            private IObserver<JihankiMessage> me;

            public _Obsererver(Jihanki parent, IObserver<JihankiMessage> me)
            {
                this.parent = parent;
                this.me = me;
            }

            public void Dispose()
            {
                if (parent != null && parent.observers.Contains(me))
                    parent.observers.Remove(me);
            }
        }

        public IDisposable Subscribe(IObserver<JihankiMessage> observer)
        {
            observers.Add(observer);
            return new _Obsererver(this, observer);
        }
    }
}
